using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Tools.UIElements
{
    public abstract class RenderableObject
    {
        protected int DrawOrder;
        public abstract void DrawAfterBegin();
        public abstract void Draw();

        public abstract void DrawAfterBegin(float alpha);
        public abstract void Draw(float alpha);
    }

    public class TextObject : RenderableObject
    {
        #region Fields

        SpriteBatch sprite_batch;
        SpriteFont font;
        Vector2 position;
        string text;
        Color color;

        float alpha = 1.0f;

        #endregion

        #region Constructors

        public TextObject(SpriteBatch sprite_batch, SpriteFont font, string text, Vector2 position, Color color)
        {
            this.sprite_batch = sprite_batch;
            this.text = text;
            this.color = color;
            this.position = position;
            this.font = font;
        }

        public TextObject(SpriteBatch sprite_batch, SpriteFont font, string text, Vector2 position)
            : this(sprite_batch, font, text, position, Color.White)
        { }

        public TextObject(SpriteBatch sprite_batch, SpriteFont font, string text, float y)
            : this(sprite_batch, font, text, Vector2.Zero)
        {
            var sm = font.MeasureString(text);

            this.position = new Vector2(sprite_batch.GraphicsDevice.Viewport.Width / 2.0f - sm.X / 2.0f, y);
        }

        public TextObject(SpriteBatch sprite_batch, SpriteFont font, string text, float y, Color color)
            : this(sprite_batch, font, text, Vector2.Zero, color)
        {
            var sm = font.MeasureString(text);

            this.position = new Vector2(sprite_batch.GraphicsDevice.Viewport.Width / 2.0f - sm.X / 2.0f, y);
        }

        #endregion

        /// <summary>
        /// Use this method if the call is inside a SpriteBatch.Begin() / SpriteBatch.End() block
        /// </summary>
        public override void DrawAfterBegin()
        {
            sprite_batch.DrawString(font, text, position, color);
        }

        /// <summary>
        /// Use this method if the call is not inside a SpriteBatch.Begin() / SpriteBatch.End() block
        /// </summary>
        public override void Draw()
        {
            sprite_batch.Begin();

            DrawAfterBegin();

            sprite_batch.End();
        }

        /// <summary>
        /// Use this method if the call is inside a SpriteBatch.Begin() / SpriteBatch.End() block
        /// </summary>
        public override void DrawAfterBegin(float alpha)
        {
            this.alpha = alpha;

            sprite_batch.DrawString(font, text, position, color * alpha);

            this.alpha = 1.0f;
        }

        /// <summary>
        /// Use this method if the call is not inside a SpriteBatch.Begin() / SpriteBatch.End() block
        /// </summary>
        public override void Draw(float alpha)
        {
            sprite_batch.Begin();

            DrawAfterBegin(alpha);

            sprite_batch.End();
        }
    }

    public class ImgObject : RenderableObject
    {
        #region Fields

        SpriteBatch sprite_batch;
        Texture2D texture;
        Rectangle rectangle;
        Color color;

        float alpha = 1.0f;

        #endregion

        #region Constructors

        public ImgObject(SpriteBatch sprite_batch, Texture2D texture, Vector2 position)
        {
            this.sprite_batch = sprite_batch;
            this.texture = texture;
            this.rectangle = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
        }

        public ImgObject(SpriteBatch sprite_batch, Texture2D texture, Vector2 position, int width, int height)
            : this(sprite_batch, texture, position)
        {
            rectangle.Width = width;
            rectangle.Height = height;
        }

        public ImgObject(SpriteBatch sprite_batch, Texture2D texture, Vector2 position, Color color)
            : this(sprite_batch, texture, position)
        {
            this.color = color;
        }

        public ImgObject(SpriteBatch sprite_batch, Texture2D texture, Vector2 position, Color color, int width, int height)
            : this(sprite_batch, texture, position, width, height)
        {
            this.color = color;
        }

        #endregion

        /// <summary>
        /// Use this method if the call is inside a SpriteBatch.Begin() / SpriteBatch.End() block
        /// </summary>
        public override void DrawAfterBegin()
        {
            sprite_batch.Draw(texture, rectangle, color);
        }

        /// <summary>
        /// Use this method if the call is not inside a SpriteBatch.Begin() / SpriteBatch.End() block
        /// </summary>
        public override void Draw()
        {
            sprite_batch.Begin();

            DrawAfterBegin();

            sprite_batch.End();
        }

        /// <summary>
        /// Use this method if the call is inside a SpriteBatch.Begin() / SpriteBatch.End() block
        /// </summary>
        public override void DrawAfterBegin(float alpha)
        {
            this.alpha = alpha;

            sprite_batch.Draw(texture, rectangle, color * alpha);

            this.alpha = 1.0f;
        }

        /// <summary>
        /// Use this method if the call is not inside a SpriteBatch.Begin() / SpriteBatch.End() block
        /// </summary>
        public override void Draw(float alpha)
        {
            sprite_batch.Begin();

            DrawAfterBegin(alpha);

            sprite_batch.End();
        }
    }
}
